package alarmapi

import (
	"encoding/json"
	"errors"
	"iot-base/common/cache"
	ca "iot-base/common/cache/alarm"
	"iot-base/common/dbconn"
	"iot-base/common/dbobj"
	"iot-base/common/idsync"
	"iot-base/common/webapi"

	"gorm.io/gorm"

	"fmt"
	"github.com/gin-gonic/gin"
)

func initAlarmCfgAPI(rp *gin.RouterGroup) {

	//sp := rp.Group("/shield/")
	//webapi.BindCrud(rp, "/shield/", &dbobj.AlarmShield{})

	fmt.Println("&&&&&&&&&&&&&&&&initAlarmCfgAPI")
	r := rp.Group("/cfg/")
	r.GET("/rule/:tid", func(c *gin.Context) {
		tid := c.Param("tid")
		if tid == "" {
			var rules []dbobj.ThingAlarmRule
			err := dbconn.DBConnection.Find(&rules).Error
			if errors.Is(err, gorm.ErrRecordNotFound) {
				err = nil
			}
			webapi.SendResult(rules, err, c)
		} else {
			var rule dbobj.ThingAlarmRule
			rule.ThingID = tid
			err := dbconn.DBConnection.First(&rule).Error
			if errors.Is(err, gorm.ErrRecordNotFound) {
				err = nil
			}
			webapi.SendResult(rule, err, c)
		}
	})
	r.PUT("/rule/", func(c *gin.Context) {
		var rule dbobj.ThingAlarmRule
		c.BindJSON(&rule)
		if rule.ThingID != "" {
			var count int64
			var err error
			err = dbconn.DBConnection.Transaction(func(tx *gorm.DB) error {
				tx.Model(&rule).Count(&count).Where("thing_id=?", rule.ThingID)
				if count == 0 {
					err = tx.Create(&rule).Error
				} else {
					err = tx.Save(&rule).Error
				}
				return err

			})
			if err == nil {
				idsync.DirtyThing(rule.ThingID)
			}

			webapi.SendResult(rule, err, c)
		} else {
			webapi.SendError("thingid not found", webapi.ParamMissed, c)
		}
	})
	r.POST("/rule/condition/:tid", func(c *gin.Context) {
		tid := c.Param("tid")
		if tid == "" {
			webapi.SendError("tid is empty", webapi.ParamMissed, c)
			return
		}
		var crule map[string]interface{}
		perr := c.ShouldBind(&crule)
		if perr != nil {
			webapi.SendError(perr.Error(), webapi.ParamMissed, c)
			return
		}
		mtargetID, _ := crule["tid"]
		if mtargetID == nil {
			webapi.SendError("target_id not found", webapi.ParamMissed, c)
			return
		}
		targetID, _ := mtargetID.(string)
		isEmpty := false
		expr, _ := crule["expression"]
		if expr == nil || expr == "" {
			isEmpty = true
		}
		if targetID == "" {
			webapi.SendError("target_id not found", webapi.ParamMissed, c)
			return
		}
		sexp, _ := expr.(string)
		crule["source_properties"] = cache.ParseExpression(sexp)
		err := dbconn.DBConnection.Transaction(func(tx *gorm.DB) error {
			var rule dbobj.ThingAlarmRule
			rule.ThingID = tid
			//var rule cache.EventExpression
			var expressions []map[string]interface{}
			err := tx.Where("thing_id=?", tid).First(&rule).Error
			if err == nil {

				if rule.AlarmConditionRule != nil {

					errj := json.Unmarshal(rule.AlarmConditionRule, &expressions)
					if errj != nil {
						return errj
					}
					isExist := false
					for index, exp := range expressions {
						if exp != nil {
							alarmId := exp["tid"]
							if alarmId == targetID {
								if isEmpty {
									expressions = append(expressions[:index], expressions[index+1:]...)
								} else {
									exp["expression"] = crule["expression"]
									exp["source_properties"] = crule["source_properties"]
									//sexp, _ := expr.(string)
									//exp["source_properties"] = cache.ParseExpression(sexp)
								}
								isExist = true
								break
							}
						}
					}
					if !isExist {
						expressions = append(expressions, crule)
					}
				} else {
					expressions = make([]map[string]interface{}, 1)
					expressions[0] = crule
				}
				rule.AlarmConditionRule, _ = json.Marshal(expressions)
				err = tx.Save(&rule).Error
			} else {
				expressions = make([]map[string]interface{}, 1)
				expressions[0] = crule
				rule.AlarmConditionRule, _ = json.Marshal(expressions)
				err = tx.Create(&rule).Error
			}
			return err

		})
		if err == nil {
			webapi.SendOK(c)
			idsync.DirtyThing(tid)
		} else {
			webapi.SendError(err.Error(), webapi.DBError, c)
		}

	})
	r.DELETE("/rule/:tid", func(c *gin.Context) {
		tid := c.Param("tid")
		if tid == "" {
			webapi.SendError("thingid not found", webapi.ParamMissed, c)
		} else {
			err := dbconn.DBConnection.Delete(&dbobj.ThingAlarmRule{}, tid).Error
			if err == nil {
				webapi.SendOK(c)
				idsync.DirtyThing(tid)
			} else {
				webapi.SendError(err.Error(), webapi.DBError, c)
			}
		}
	})

	r.GET("/shield/:typeid/:tid/:aid", func(c *gin.Context) {
		tid := c.Param("tid")
		if tid == "" {
			webapi.SendError("targetid not found", webapi.ParamMissed, c)
		} else {
			aid := c.Param("aid")
			if aid == "" {
				webapi.SendError("aid not found", webapi.ParamMissed, c)
				return
			}
			typeid := c.Param("typeid")
			if typeid == "" {
				webapi.SendError("typeid not found", webapi.ParamMissed, c)
				return
			}
			var alarmShield dbobj.AlarmShield
			err := dbconn.DBConnection.Where("target_id=? and alarm_id=? and target_type=?",
				tid, aid, typeid).First(&alarmShield).Error
			webapi.SendResult(alarmShield, err, c)
		}
	})
	r.GET("/shield/:typeid/:tid", func(c *gin.Context) {
		tid := c.Param("tid")
		if tid == "" {
			webapi.SendError("targetid not found", webapi.ParamMissed, c)
		} else {

			typeid := c.Param("typeid")
			if typeid == "" {
				webapi.SendError("typeid not found", webapi.ParamMissed, c)
				return
			}

			var alarmShield []dbobj.AlarmShield
			err := dbconn.DBConnection.Where("target_id=? and target_type=?",
				tid, typeid).Find(&alarmShield).Error
			webapi.SendResult(alarmShield, err, c)
		}
	})
	r.PUT("/shield/", func(c *gin.Context) {
		var alarmShield dbobj.AlarmShield
		c.ShouldBind(&alarmShield)
		if alarmShield.TargetType == "" || alarmShield.TargetID == "" || alarmShield.AlarmID == "" {
			webapi.SendError("shield is empty", webapi.ParamMissed, c)
			return
		}
		err := dbconn.DBConnection.Transaction(func(tx *gorm.DB) error {
			var alarmShieldOld dbobj.AlarmShield
			err := tx.Where("target_id=? and target_type=? and alarm_id = ?", alarmShield.TargetID,
				alarmShield.TargetType, alarmShield.AlarmID).First(&alarmShieldOld).Error
			if err == nil {
				alarmShield.UID = alarmShieldOld.UID
				derr := tx.Save(&alarmShield).Error
				return derr
			}
			alarmShield.UID = 0
			derr := tx.Create(&alarmShield).Error
			return derr

		})
		if err == nil {
			ca.DirtyAlarmShield(alarmShield.TargetType, alarmShield.TargetID, alarmShield.AlarmID)
		}

		webapi.SendResult(alarmShield, err, c)
	})

}
